package com.huan.quartz.quartz;

import com.huan.quartz.common.JobStatus;
import com.huan.quartz.domain.QuartzJobCfg;
import com.huan.quartz.exception.QuartzJobException;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * quartz job service impl
 *
 * @author huan.fu
 * @date 2018/9/10 - 15:55
 */
@Slf4j
@Service
public class QuartzServiceImpl implements QuartzService {

	@Autowired
	private Scheduler scheduler;

	/**
	 * 默认的 job 的组名
	 */
	private static final String DEFAULT_JOB_GROUP = "JOB_GROUP_NAME";

	@Override
	public void addQuartzJob(QuartzJobCfg job) {
		addQuartzJob(job, loadClass(job.getJobClass()));
	}

	public void addQuartzJob(QuartzJobCfg job, Class<? extends Job> clazz) {
		JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), DEFAULT_JOB_GROUP).usingJobData("jobName", job.getJobName()).build();
		CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), DEFAULT_JOB_GROUP).withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
		try {
			if (JobStatus.isDisables(job.getJobStatus())) {
				pauseQuartzJob(job);
			} else {
				scheduler.scheduleJob(jobDetail, cronTrigger);
			}
			if (!scheduler.isStarted()) {
				scheduler.start();
			}
		} catch (SchedulerException e) {
			throw new QuartzJobException("添加 quartz job 失败", e);
		}
	}

	@Override
	public void updateQuartzJob(QuartzJobCfg job) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), DEFAULT_JOB_GROUP);
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
			scheduler.rescheduleJob(triggerKey, trigger);
			if (JobStatus.isDisables(job.getJobStatus())) {
				pauseQuartzJob(job);
			}
		} catch (SchedulerException e) {
			throw new QuartzJobException("更新 job 失败", e);
		}
	}

	@Override
	public void deleteQuartzJob(QuartzJobCfg job) {
		Optional.of(JobKey.jobKey(job.getJobName(), DEFAULT_JOB_GROUP))
				.ifPresent(jobKey -> {
					try {
						scheduler.deleteJob(jobKey);
					} catch (SchedulerException e) {
						throw new QuartzJobException("删除 job 失败.", e);
					}
				});
	}

	@Override
	public void pauseQuartzJob(QuartzJobCfg job) {
		Optional.of(JobKey.jobKey(job.getJobName(), DEFAULT_JOB_GROUP)).ifPresent(jobKey -> {
			try {
				scheduler.pauseJob(jobKey);
			} catch (SchedulerException e) {
				throw new QuartzJobException("暂停 job 失败", e);
			}
		});
	}

	@Override
	public void resumeQuartzJob(QuartzJobCfg job) {
		Optional.of(JobKey.jobKey(job.getJobName(), DEFAULT_JOB_GROUP))
				.ifPresent(jobKey -> {
					try {
						scheduler.resumeJob(jobKey);
					} catch (SchedulerException e) {
						throw new QuartzJobException("恢复 job 失败.", e);
					}
				});
	}

	@Override
	public void immediateExecuteJob(QuartzJobCfg job) {
		Optional.of(JobKey.jobKey(job.getJobName(), DEFAULT_JOB_GROUP))
				.ifPresent(jobKey -> {
					try {
						scheduler.triggerJob(jobKey);
					} catch (SchedulerException e) {
						throw new QuartzJobException("立即执行一次 job 失败.", e);
					}
				});
	}

	@Override
	public void updateQuartzJobExecuteClass(byte[] bytes, QuartzJobCfg job) {
		try {
			deleteQuartzJob(job);
			addQuartzJob(job, (Class<? extends Job>) new QuartzClassLoader(bytes).loadClass(job.getJobClass()));
		} catch (ClassNotFoundException e) {
			throw new QuartzJobException("无法加载类");
		}
	}

	/**
	 * 加载 class
	 *
	 * @param className
	 * @return
	 */
	public Class<? extends Job> loadClass(String className) {
		try {
			return (Class<? extends Job>) Class.forName(className);
		} catch (ClassNotFoundException e) {
			throw new QuartzJobException(String.format("[%s]对应的类找不到.", className));
		}
	}
}
